/**************************************************************************************
* 
*	Project Name : S3C6410 Validation
*
*	Copyright 2008 by Samsung Electronics, Inc.
*	All rights reserved.
*
*	Project Description :
*		This software is only for validating functions of the S3C6410.
*		Anybody can use this software without our permission.
*  
*--------------------------------------------------------------------------------------
* 
*	File Name : i2s.c
*  
*	File Description : This file implements the WM8753 driver functions for I2S.
*
*	Author : Sung-Hyun,Na
*	Dept. : AP Development Team
*	Created Date : 2008/02/29
*	Version : 0.1 
* 
*	History
*	- Created(Sunghyun,Na 2008/02/01)
*	- Merge I2S Multi channel(Audio Controller 2)
*   
**************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "intc.h"
#include "gpio.h"

#include "audio.h"
#include "i2s.h"

//Descript I2S SFR
typedef enum 
{
	rI2SCON = 0x0,		// IIS Control Register (R/W)
	rI2SMOD = 0x4,		// IIS Mode Register (R/W)
	rI2SFIC = 0x8,		// IIS FIFO Control Register (R/W)
	rI2SPSR = 0xc,   		// IIS Clock Divider Control Register (R/W)
	rI2STXD = 0x10,		// IIS Tx Data FIFO (W)
	rI2SRXD	= 0x14,		// IIS Rx Data FIFO (R)	
}I2S_SFR;
void I2S_Outp32(AUDIO_PORT , I2S_SFR, u32);
u32  I2S_Inp32(AUDIO_PORT, I2S_SFR);


// En : Enable
// Da : disable
// Clr : Clrear
// St : Status
// Pa : Pause (~Enable)
// Fl : Flush
#define I2S_ClrOverrunIntr				(1 << 19)
#define I2S_EnOverrunIntr				(1 << 18)
#define I2S_ClrUnderrunIntr			(1 << 17)
#define I2S_EnUnderrunIntr			(1 << 16)

#define I2S_StLRCLK					(1 << 11)
#define I2S_StTxFifoEmpty				(1 << 10)
#define I2S_StRxFifoEmpty				(1 <<  9)
#define I2S_StTxFifoFull					(1 << 8)
#define I2S_StRxFifoFull				(1 << 7)
#define I2S_StRxFifoCnt				(0x1f << 0)
#define I2S_StTxFifoCnt					(0x1f << 8)
#define I2S_PaTxDma					(1 << 6)
#define I2S_PaRxDma					(1 << 5)
#define I2S_PaTxInterface				(1 << 4)
#define I2S_PaRxInterface				(1 << 3)
#define I2S_EnTxDma					(1 << 2)
#define I2S_EnRxDma					(1 << 1)
#define I2S_EnI2sInterface				(1 << 0)
#define I2S_FluTxFifo					(1 << 15)
#define I2S_FluRxFifo					(1 << 7)
#define I2S_EnPrescaler				(1 << 15)


//Define global variables
static I2S_Infor		g_oI2SInfor[I2S_CONNUM];
/*---------------------------------- Init Functions  ---------------------------------*/
//////////
// Function Name : I2S_GetInfor
// Function Description : This function return Address of structure for I2S Information
// Input : 	uPort - I2S Port Number 
// Output : 	I2S_Infor* - Address of i2S Information structure.
// Version : v0.1
I2S_Infor* I2S_GetInfor(AUDIO_PORT ePort)
{
	 if (ePort == AUDIO_PORT1)
		return &(g_oI2SInfor[AUDIO_PORT1]);
	else  if (ePort == AUDIO_PORT0)
		return &(g_oI2SInfor[AUDIO_PORT0]);
	else  if (ePort == AUDIO_PORT2)
		return &(g_oI2SInfor[AUDIO_PORT2]);
	else
	{	
		Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
		Assert(0);
	}
}

//////////
// Function Name : I2S_Init
// Function Description : This function initializes a certain I2S Port.
// Input : 	uPort - I2S Port Number 
// Output : 	TRUE - Memory Device is reset
//				FALSE - Memory Device is not reset because of ERROR
// Version : v0.1
u32 I2S_Init(AUDIO_PORT ePort)
{
	I2S_Infor* pInfor;
	pInfor = I2S_GetInfor(ePort);
	
	if(ePort == AUDIO_PORT0)
	{	
		//SMDK Configuration
		pInfor->m_uCodec			= WM8990;
		pInfor->m_eLine				= CodecPort_1st;
		//Sample Rate
		pInfor->m_uSamplingRate 		= 48000;
		//DMA Unit
		pInfor->m_eDmaUnit 			= DMA0;	
		//IP Configuartion
		pInfor->m_eDataFormat		= I2SFormat;
		pInfor->m_eWordLength		= Word16;
		pInfor->m_eCLKSRC			= I2S_MOUT_EPLL;
		pInfor->m_eIFMode			= TXRXBoth;
		pInfor->m_eOpMode			= Master;
		pInfor->m_eLRCLKPolarity		= RightHigh;
		pInfor->m_eRFS				= RFS_768fs;	
		pInfor->m_eBFS				= BFS_48fs;		
		//Buffer
		pInfor->m_pI2SRxAddr 		= (u32* )0x5100002c;		
		pInfor->m_sI2SRxSize			= I2S_RECORD_LENGTH;				
		pInfor->m_pI2STxAddr 		= (u32* )0x5100002c;
		pInfor->m_sI2STxSize			= I2S_RECORD_LENGTH;
		
		pInfor->m_pMemI2SRx		= pInfor->m_pI2SRxAddr;
		pInfor->m_pMemI2STx			= pInfor->m_pI2STxAddr;
		pInfor->m_sI2SRxPointer		= pInfor->m_sI2SRxSize;
		pInfor->m_sI2STxPointer		= pInfor->m_sI2STxSize;
		//DMA Unit Select
		pInfor->m_uNumDma			= NUM_DMA0;
		
		//DMA Channel Select and initialize channel structure.
		//TX Channel
		pInfor->m_eDmaTxCh			= DMA_A;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaTxCh, &(pInfor->m_oI2STxDma));
		//RX Channel
		pInfor->m_eDmaRxCh			= DMA_B;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaRxCh, &(pInfor->m_oI2SRxDma));		
		pInfor->m_usI2STxDone		= FALSE;
		pInfor->m_usI2SRxDone		= FALSE;		
	}
	else if(ePort == AUDIO_PORT1)
	{
		//SMDK Configuration
		pInfor->m_uCodec			= WM8580;
		pInfor->m_eLine				= CodecPort_2nd;
		//Sample Rate
		pInfor->m_uSamplingRate 		= 48000;
		//DMA Unit
		pInfor->m_eDmaUnit 			= DMA1;	
		//IP Configuartion
		pInfor->m_eDataFormat		= I2SFormat;
		pInfor->m_eWordLength		= Word16;
		pInfor->m_eCLKSRC			= I2S_MOUT_EPLL;
		pInfor->m_eIFMode			= TXRXBoth;
		pInfor->m_eOpMode			= Master;
		pInfor->m_eLRCLKPolarity		= RightHigh;
		pInfor->m_eRFS				= RFS_768fs;	
		pInfor->m_eBFS				= BFS_48fs;	
		
		//Buffer
		pInfor->m_pI2SRxAddr 		= (u32* )0x5100002c;		
		pInfor->m_sI2SRxSize			= I2S_RECORD_LENGTH;				
		pInfor->m_pI2STxAddr 		= (u32* )0x5100002c;
		pInfor->m_sI2STxSize			= I2S_RECORD_LENGTH;
		
		pInfor->m_pMemI2SRx		= pInfor->m_pI2SRxAddr;
		pInfor->m_pMemI2STx			= pInfor->m_pI2STxAddr;
		pInfor->m_sI2SRxPointer		= pInfor->m_sI2SRxSize;
		pInfor->m_sI2STxPointer		= pInfor->m_sI2STxSize;
		//DMA Unit Select
		pInfor->m_uNumDma			= NUM_DMA1;
		
		//DMA Channel Select and initialize channel structure.
		//TX Channel
		pInfor->m_eDmaTxCh			= DMA_A;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaTxCh, &(pInfor->m_oI2STxDma));
		//RX Channel
		pInfor->m_eDmaRxCh			= DMA_B;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaRxCh, &(pInfor->m_oI2SRxDma));		
		pInfor->m_usI2STxDone		= FALSE;
		pInfor->m_usI2SRxDone		= FALSE;	
	}
	else if(ePort == AUDIO_PORT2)
	{
		//SMDK Configuration
		pInfor->m_uCodec			= WM8580;
		pInfor->m_eLine				= CodecPort_1st;			//Only WM8580 PAIF
		//Sample Rate
		pInfor->m_uSamplingRate 		= 48000;
		//DMA Unit
		pInfor->m_eDmaUnit 			= DMA0;	
		//IP Configuartion
		pInfor->m_eDataFormat		= I2SFormat;
		pInfor->m_eWordLength		= Word16;
		pInfor->m_eCLKSRC			= I2S_MOUT_EPLL;
		pInfor->m_eIFMode			= TXRXBoth;
		pInfor->m_eOpMode			= Master;
		pInfor->m_eLRCLKPolarity		= RightHigh;
		pInfor->m_eRFS				= RFS_768fs;	
		pInfor->m_eBFS				= BFS_48fs;	
		#ifdef S3C6410										//Only I2S MultiChannel
		pInfor->m_eDCE				= I2S_Tx0;
		pInfor->m_eFifo1CDD			= NoDiscard;
		pInfor->m_eFifo2CDD			= NoDiscard;
		#endif
		//Buffer
		pInfor->m_pI2SRxAddr 		= (u32* )0x5100002c;		
		pInfor->m_sI2SRxSize			= I2S_RECORD_LENGTH;				
		pInfor->m_pI2STxAddr 		= (u32* )0x5100002c;
		pInfor->m_sI2STxSize			= I2S_RECORD_LENGTH;
		
		pInfor->m_pMemI2SRx		= pInfor->m_pI2SRxAddr;
		pInfor->m_pMemI2STx			= pInfor->m_pI2STxAddr;
		pInfor->m_sI2SRxPointer		= pInfor->m_sI2SRxSize;
		pInfor->m_sI2STxPointer		= pInfor->m_sI2STxSize;
		//DMA Unit Select
		pInfor->m_uNumDma			= NUM_DMA0;
		
		//DMA Channel Select and initialize channel structure.
		//TX Channel
		pInfor->m_eDmaTxCh			= DMA_C;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaTxCh, &(pInfor->m_oI2STxDma));
		//RX Channel
		pInfor->m_eDmaRxCh			= DMA_D;
		DMAC_InitCh(pInfor->m_eDmaUnit , pInfor->m_eDmaRxCh, &(pInfor->m_oI2SRxDma));		
		pInfor->m_usI2STxDone		= FALSE;
		pInfor->m_usI2SRxDone		= FALSE;	
	}
	else
	{
		Disp("S3C6410 dose not support Audio Port %d\n",ePort);
		Assert(0);
		return FALSE;
	}			
	return TRUE;
}

//////////
// Function Name : I2S_SetI2SInfor
// Function Description : 
// Input : 	ePort - I2S Port Number 
// 			peInfor - I2S Information of set 
// Version : v0.1
void I2S_SetI2SInfor(AUDIO_PORT ePort, I2S_Infor* peInfor)
{
	 if (ePort == AUDIO_PORT1)
	 	memcpy((u32 *)(&g_oI2SInfor[AUDIO_PORT1]), (u32 *)peInfor, sizeof(I2S_Infor));
	else  if (ePort == AUDIO_PORT0)
		memcpy((u32 *)(&g_oI2SInfor[AUDIO_PORT0]), (u32 *)peInfor, sizeof(I2S_Infor));
	else
	{	
		Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
		Assert(0);
	}
}

//////////
// Function Name : I2S_CpyI2SInfor
// Function Description : This function copy i2s information structure
// Input : 	ePort - I2S Port Number 
// 			peTemp - address of structure copied
// Version : v0.1
u8 I2S_CpyI2SInfor(AUDIO_PORT ePort, u32* peTemp)
{
	if (ePort == AUDIO_PORT0)
	{
		memcpy(peTemp, (u32 *)(&g_oI2SInfor[AUDIO_PORT0]), sizeof(I2S_Infor));
		return TRUE;
	}
	else if(ePort == AUDIO_PORT1)
	{
		memcpy(peTemp, (u32 *)(&g_oI2SInfor[AUDIO_PORT1]), sizeof(I2S_Infor));
		return TRUE;
	}
	else
	{
		Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
		Assert(0);
		return FALSE;
	}
}

//////////
// Function Name : I2S_SetIntrDone
// Function Description : This function set Global indicator for isr.
// Input : 	eInt 	- Interrup Source
// 			usBool	- TRUE/FALSE
// Output :	None
// Version : v0.0
void I2S_SetIntrDone(AUDIO_PORT ePort, I2S_IFMode eCh, u8 usBool)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly)			pInfor->m_usI2SRxDone = usBool;
	else if ( eCh == TXOnly)		pInfor->m_usI2STxDone = usBool;
	else if ( eCh == TXRXBoth)	
	{
		pInfor->m_usI2SRxDone = usBool;
		pInfor->m_usI2SRxDone = usBool;
	}	
	else
		Assert('0');
}

//////////
// Function Name : I2S_GetIntrDone
// Function Description : This function return Global indicator
// Input : 	eInt 	- Interrup Source
// Output :	u8
// Version : v0.0
u8 I2S_GetIntrDone(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly)			return pInfor->m_usI2SRxDone;
	else if ( eCh == TXOnly)		return pInfor->m_usI2STxDone;
	else if ( eCh == TXRXBoth)	
	{
		if (pInfor->m_usI2SRxDone == pInfor->m_usI2SRxDone)
			return pInfor->m_usI2SRxDone;
		else 
			return -1;
	}	
	else
		return -1;
}

//////////
// Function Name : I2S_InitBuffer
// Function Description : This function set Memory Buffer
// Input : 	eCh 	- I2S Interface Slot
// 			u32* 	- New Address
//			u32 	- New Data Size
// Output :	None
// Version : v0.0
void I2S_InitBuffer(AUDIO_PORT ePort, I2S_IFMode eCh, u32* pAddr, u32 uDataSize)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly )
	{
		pInfor->m_pMemI2SRx = pAddr;
		pInfor->m_sI2SRxPointer = uDataSize;
	}
	else if ( eCh == TXOnly )
	{
		pInfor->m_pMemI2STx = pAddr;
		pInfor->m_sI2STxPointer = uDataSize;
	}	
	else 
		Assert(0);	
}

//////////
// Function Name : I2S_PutDataMem
// Function Description : This function put data PCM Data Memory Buffer
// Input : 	ePort - I2S Port Number 
// 			I2S_IFMode - RX or TX
// 			pData - Address Returned Data
// Output :	s32 - Current Buffer Counter
// Version : v0.0
s32 I2S_PutDataMem(AUDIO_PORT ePort, I2S_IFMode eCh, u32* pData)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly )
	{
		*(pInfor->m_pMemI2SRx++) = *pData;
		pInfor->m_sI2SRxPointer -= 4;
		return pInfor->m_sI2SRxPointer;
	}
	else if ( eCh == TXOnly )
	{
		*(pInfor->m_pMemI2STx++) = *pData;
		pInfor->m_sI2STxPointer -= 4;
		return pInfor->m_sI2STxPointer;
	}
	else
	{
		Assert(0);
		return FALSE;
	}	
}

//////////
// Function Name : I2S_PopDataMem
// Function Description : This function pop data PCM Data in the Memory Buffer
// Input : 	ePort - I2S Port Number 
// 			I2S_IFMode - RX or TX
// Output :	u32 - PCM Data
// Version : v0.0
s32 I2S_PopDataMem(AUDIO_PORT ePort, I2S_IFMode eCh, u32* pData)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly )
	{
		*pData = *(pInfor->m_pMemI2SRx++);		
		pInfor->m_sI2SRxPointer -= 4;	
		return pInfor->m_sI2SRxPointer;
	}
	else if ( eCh == TXOnly )
	{
		*pData = *(pInfor->m_pMemI2STx++);
		pInfor->m_sI2STxPointer -= 4;	
		return pInfor->m_sI2STxPointer;
	}
	else
	{
		Assert(0);
		return FALSE;
	}	
}

/*---------------------------------- APIs of Clock ---------------------------------*/
void I2S_SetCDCLKOut(AUDIO_PORT ePort, I2S_CLKSRC eCLKSRC, u32 uSampleRate, I2S_RFS eRFSDivider)
{	
	double dVclkSrc, dTempVal;
	double dTempCDCLK;
	I2S_Infor* pInfor = I2S_GetInfor(ePort);	
	Disp("Sample Rate is %dHz\n", uSampleRate);
	if (eRFSDivider == RFS_512fs)
		dTempCDCLK = (double) uSampleRate * 512;
	else if (eRFSDivider == RFS_256fs)
		dTempCDCLK = (double) uSampleRate * 256;
	else if (eRFSDivider == RFS_384fs)
		dTempCDCLK = (double) uSampleRate * 384;
	else if (eRFSDivider == RFS_768fs)
		dTempCDCLK = (double) uSampleRate * 768;	
	UART_Printf("User Sets IISCDCLK is %3.3fMHz\n",dTempCDCLK/1000000);
	
	if ( eCLKSRC == I2S_PCLK)
	{
		SYSC_GetClkInform();
		UART_Printf("Source CLK is PCLK : ");
		dVclkSrc = (double) (g_PCLK);
	}
	else 
	{
		I2S_SetAudioCLK(ePort, eCLKSRC);	
		switch(eCLKSRC)
		{
			case I2S_MOUT_EPLL:
				dVclkSrc = I2S_SetEPLL(ePort, dTempCDCLK); 
				UART_Printf("Source CLK is AudioCLK%d, Epll : ",(u32) ePort);
				break;
			case I2S_DOUT_MPLL:
				SYSC_GetClkInform();
				dVclkSrc = (double) (g_MPLL);
				UART_Printf("Source CLK is AudioCLK%d, Mpll : ",(u32) ePort);
				break;
			case I2S_FIN:
				dVclkSrc =  FIN; 
				UART_Printf("Source CLK is AudioCLK%d, Fin of Pll : ",(u32) ePort);
				break;
			case I2S_EXTERNALCDCLK:
				dVclkSrc = I2S_EXTERNALCLK;	
				UART_Printf("Source CLK is AudioCLK%d, External clk of I2SCDCLK : ",(u32) ePort);
				break;			
			case I2S_PCLK:
			default:
				Assert(0);
				break;
		}	
		if (ePort == AUDIO_PORT0)		SYSC_SetDIV(eAUDIO0_RATIO, 0);
		else if (ePort == AUDIO_PORT1)	SYSC_SetDIV(eAUDIO1_RATIO, 0);
		else if (ePort == AUDIO_PORT2)	SYSC_SetDIV(eAUDIO2_RATIO, 0);
		else		Assert(0);
	}
	dTempVal = dVclkSrc/dTempCDCLK;	
	if ( ((int)(dTempVal*10) % 10) < 5)		//Round off 
		dTempVal = dTempVal-1;	
	UART_Printf("%3.3fMHz\n", dVclkSrc / 1000000);		
	UART_Printf("Prescaler Value is 0x%x\n", (u32) dTempVal);	
	UART_Printf("IISCDCLK is %3.3fMHz\n",(dVclkSrc/(((u32)dTempVal)+1))/1000000);
	I2SPSR_SetPrescaler(ePort, (u32)(dTempVal));		
	//
	//uTemp = I2S_Inp32(ePort, rI2SCON);
	//uTemp |=I2S_EnI2sInterface;			//Enable I2SI/F
	//uTemp &=  ~I2S_EnTxDma & ~I2S_PaTxDma & ~I2S_PaTxInterface & ~I2S_EnTxDma & ~I2S_PaRxDma & ~I2S_PaRxInterface & ~I2S_EnUnderrunIntr & I2S_EnOverrunIntr;		//Disable Pause RX DMA, RX I/F
	//I2S_Outp32(ePort, rI2SCON, uTemp);
}

//////////
// Function Name : I2S_SetAudioCLK
// Function Description : 
//   This function Select AUDIOCLK
// Input : 	ePort 		- I2S controller number
//			eClkSrc		- I2S clock source
// Output : None
// Version : v0.1
void I2S_SetAudioCLK(AUDIO_PORT ePort, I2S_CLKSRC eClkSrc)
{
	if(ePort == AUDIO_PORT0)
	{
		if(eClkSrc == I2S_MOUT_EPLL) 				SYSC_ClkSrc(eAUDIO0_MOUTEPLL);				
		else if (eClkSrc == I2S_DOUT_MPLL) 		SYSC_ClkSrc(eAUDIO0_DOUTMPLL);
		else if (eClkSrc == I2S_FIN) 				SYSC_ClkSrc(eAUDIO0_FINEPLL);
		else if (eClkSrc == I2S_EXTERNALCDCLK) 	SYSC_ClkSrc(eAUDIO0_I2SCDCLK0);
	}
	else if(ePort == AUDIO_PORT1)
	{
		if(eClkSrc == I2S_MOUT_EPLL) 				SYSC_ClkSrc(eAUDIO1_MOUTEPLL);			
		else if (eClkSrc == I2S_DOUT_MPLL) 		SYSC_ClkSrc(eAUDIO1_DOUTMPLL);
		else if (eClkSrc == I2S_FIN) 				SYSC_ClkSrc(eAUDIO1_FINEPLL);
		else if (eClkSrc == I2S_EXTERNALCDCLK) 	SYSC_ClkSrc(eAUDIO1_I2SCDCLK1);
	}
	else if(ePort == AUDIO_PORT2)
	{
		if(eClkSrc == I2S_MOUT_EPLL) 				SYSC_ClkSrc(eAUDIO2_MOUTEPLL);			
		else if (eClkSrc == I2S_DOUT_MPLL) 		SYSC_ClkSrc(eAUDIO2_DOUTMPLL);
		else if (eClkSrc == I2S_FIN) 				SYSC_ClkSrc(eAUDIO2_FINEPLL);
		else if (eClkSrc == I2S_EXTERNALCDCLK) 	SYSC_ClkSrc(eAUDIO2_I2SCDCLK1);
		else if (eClkSrc == I2S_PCMEXT1) 			SYSC_ClkSrc(eAUDIO2_PCMCDCLK);
	}
	else Assert("0");
}
//////////
// Function Name : I2S_GetPRSVal
// Function Description : 
//   This function change M,P,S,K Value of EPLL.
// Input : 	ePort -> Sample Frequency, RFS, BFS 
// Output : Output Frequency of EPLL
// Version : 
// Example :
//	
//	RFS	: 384fs ( I2SCDCLK/384 = 44.09KHz)
//	BFS : 48fs (RFS*48 = 2.116MHz)
u32 I2S_GetPRSVal(AUDIO_PORT ePort, u32 uSourceCLK, u32 uTargetCLK)
{
	double dVclkSrc = (double) uSourceCLK;
	double dTempCDCLK = (double) uTargetCLK; 
	double dTempVal;
	dTempVal = dVclkSrc/dTempCDCLK;		
	if ( ((int)(dTempVal*10) % 10) < 5)		//Round off 
		dTempVal = dTempVal-1;
	
	UART_Printf("Source CLK is %3.3fMHz\n", dVclkSrc / 1000000);	
	UART_Printf("User Sets IISCDCLK is %3.3fMHz\n",(double)(dTempCDCLK/1000000));
	UART_Printf("Prescaler Value is 0x%x\n", (u32) dTempVal);	
	UART_Printf("IISCDCLK is %3.3fMHz\n",dVclkSrc/((u32)dTempVal+1)/1000000);	
	return (u32)(dTempVal);

}
//////////
// Function Name : I2S_SetEPLL
// Function Description : 
//   This function select one of  M,P,S,K Value of EPLL.
// Input : 	ePort -> Sample Frequency, RFS, BFS 
//			dTargetClk -> Target Frequency
// Output : Output Frequency of EPLL
// Version : 
// Example :
//	
//	RFS	: 384fs ( I2SCDCLK/384 = 44.09KHz)
//	BFS : 48fs (RFS*48 = 2.116MHz)
double I2S_SetEPLL(AUDIO_PORT ePort, double dTargetClk)
{
	double fFOUTEpll, fDivdValue, fTemp;
	u8 ucSel = 0;
	u16 uPdiv, uMdiv, uSdiv, uKdiv;
	u32 uDivdValue;
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	fFOUTEpll = dTargetClk;
	fTemp = 73728000;
	while(1)
	{
		fDivdValue = fTemp  / fFOUTEpll;
		uDivdValue = (u32) fDivdValue;
		fTemp = fDivdValue - (double) uDivdValue;
		if (fTemp < 0.0001 || fTemp > 0.9999)
		{
			fFOUTEpll = fFOUTEpll*fDivdValue;
			UART_Printf("CLKAUDIO%d out is %3.3fMHz\n", ePort, fFOUTEpll/1000000);
			break;
		}
		switch(ucSel)
		{
			case 0:
				fTemp = 67738000;
				ucSel++;
				break;
			case 1:
				fTemp = 49152000;
				ucSel++;
				break;
			case 2:
				fTemp = 45158000;
				ucSel++;
				break;
			case 3:
				fTemp = 32768000;
				ucSel++;
				break;
		}
	}
	switch(ucSel)
	{
		case 0:				//73.728MHz
			uMdiv = 49;
			uKdiv = 9961;
			uPdiv = 1;	
			uSdiv = 3;			
			break;
		case 1:				//67.738MHz
			uMdiv = 45;
			uKdiv = 10398;
			uPdiv = 1;	
			uSdiv = 3;			
			break;
		case 2:				//49.152MHz
			uMdiv = 32;
			uKdiv = 50297;
			uPdiv = 2;	
			uSdiv = 2;
			break;
		case 3:				//45.158MHz
			uMdiv = 90;
			uKdiv = 20709;
			uPdiv = 3;	
			uSdiv = 3;
			break;
		case 4:				//32.768MHz
			uMdiv = 21;
			uKdiv = 55400;
			uPdiv = 1;	
			uSdiv = 3;
			break;
	}
	SYSC_SetPLL(eEPLL, uMdiv, uPdiv, uSdiv, uKdiv);
	SYSC_ClkSrc(eEPLL_FOUT);
	Delay(1000);	
	#if 1		//Epll Clkpad out 
	SYSC_CtrlCLKOUT(eCLKOUT_EPLLOUT,  0);
	GPIO_SetFunctionEach(eGPIO_F, eGPIO_14, 3);
	GPIO_SetPullUpDownEach(eGPIO_F, eGPIO_14, 0);
	#endif 
	return fFOUTEpll;
}

/*---------------------------------- ISR Routines ---------------------------------*/
//////////
// Function Name : ISR_I2S
// Function Description : 
//   This function is interrupt service routine for I2S Interrrupt request.
//   It stops I2S Controller ,display which interrupt and set interrupt check variable.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
void __irq ISR_I2S(void)
{
	u32 uCnt;
	I2S_IFMode eIntrCon;
	INTC_Disable(NUM_I2S);	
	for (uCnt = 0; uCnt < (AUDIO_NUM); uCnt++)
	{
		eIntrCon = I2SCON_ChkInterrupt((AUDIO_PORT) uCnt);
		if ( eIntrCon != TXRXNeither )
		{
			switch(eIntrCon)
			{
				case RXOnly:
					UART_Printf("\nI2S Controller %d is RX Fifo over run!!\n", uCnt);
					I2S_SetIntrDone((AUDIO_PORT)uCnt, RXOnly, TRUE);
					I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_RX, DISABLE);
					I2SCON_ClrOverIntr((AUDIO_PORT)uCnt);	
					break;
				case TXOnly:
					UART_Printf("\nI2S Controller %d is TX Fifo under run!!\n", uCnt);
					I2S_SetIntrDone((AUDIO_PORT)uCnt, TXOnly, TRUE);
					I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_TX, DISABLE);
					I2SCON_ClrUnderIntr((AUDIO_PORT)uCnt);	
					break;
				case TXRXBoth:
					UART_Printf("\nI2S Controller %d is TX Fifo under run!!\n", uCnt);
					UART_Printf("\nI2S Controller %d is RX Fifo over run!!\n", uCnt);
					I2S_SetIntrDone((AUDIO_PORT)uCnt, RXOnly, TRUE);
					I2S_SetIntrDone((AUDIO_PORT)uCnt, TXOnly, TRUE);
					I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_RX, DISABLE);
					I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_TX, DISABLE);
					I2SCON_ClrOverIntr((AUDIO_PORT)uCnt);	
					I2SCON_ClrUnderIntr((AUDIO_PORT)uCnt);	
					break;				
			}			
		}
	}
	INTC_Enable(NUM_I2S);
}

//////////
// Function Name : ISR_I2SOverrunTransfer
// Function Description : 
//   This function is interrupt service routine for I2S overrun Interrrupt overrun request.
//   It is for test possibilty of overrun interrupt using transfer.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
void __irq ISR_I2SOverrunTransfer(void)
{
	u32 uCnt;
	u32 uData;
	I2S_IFMode eIntrCon;	
	// Disable Interrupt Controller
	INTC_Disable(NUM_I2S);
	//Find I2S Controller generated
	for (uCnt = 0; uCnt < (AUDIO_NUM); uCnt++)
	{
		eIntrCon = I2SCON_ChkInterrupt((AUDIO_PORT) uCnt);
		if ( eIntrCon == RXOnly )										// Find RX Overrun Interrupt 
		{
			I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_RX, DISABLE);
			while(1)
			{
				uData = I2SRXD_GetData((AUDIO_PORT) uCnt);									//Data Transfer	
				I2S_PutDataMem((AUDIO_PORT) uCnt, RXOnly, &uData);
				if (I2SCON_ChkFIFOEmpty((AUDIO_PORT) uCnt, RXOnly))
					break;
			}
			I2SCON_ClrOverIntr((AUDIO_PORT)uCnt);	
			INTC_ClearVectAddr();
			
			if (I2S_GetInfor((AUDIO_PORT)uCnt)->m_sI2SRxPointer <= 0)
				I2S_SetIntrDone((AUDIO_PORT)uCnt, RXOnly, TRUE);
			else
			{
				I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_RX, ENABLE);
				INTC_Enable(NUM_I2S);
			}
		}		
	}
}

//////////
// Function Name : ISR_I2SUnderrunTransfer
// Function Description : 
//   This function is interrupt service routine for I2S underrun Interrrupt overrun request.
//   It is for test possibilty of underrun interrupt using transfer.
// Input : 	None
// Output : None
// Version : 0.0
// Example 
void __irq ISR_I2SUnderrunTransfer(void)
{
	u32 uCnt;
	u32 uData;
	I2S_IFMode eIntrCon;	
	// Disable Interrupt Controller
	INTC_Disable(NUM_I2S);
	//Find I2S Controller generated
	for (uCnt = 0; uCnt < (AUDIO_NUM); uCnt++)
	{
		eIntrCon = I2SCON_ChkInterrupt((AUDIO_PORT) uCnt);
		if ( eIntrCon == TXOnly )										// Find RX Overrun Interrupt 
		{
			I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_TX, DISABLE);
			while(1)
			{
				I2S_PopDataMem((AUDIO_PORT) uCnt, TXOnly, &uData);
				I2STXD_PutData((AUDIO_PORT) uCnt, uData);									//Data Transfer	
				
				if (I2SCON_ChkFIFOFull((AUDIO_PORT) uCnt, TXOnly))
					break;
			}
			I2SCON_ClrUnderIntr((AUDIO_PORT)uCnt);	
			INTC_ClearVectAddr();
			
			if (I2S_GetInfor((AUDIO_PORT)uCnt)->m_sI2STxPointer <= 0)
				I2S_SetIntrDone((AUDIO_PORT)uCnt, TXOnly, TRUE);
			else
			{
				I2SCON_EnableIntr((AUDIO_PORT) uCnt, I2S_TX, ENABLE);
				INTC_Enable(NUM_I2S);
			}
		}		
	}

}
/*---------------------------------- APIs of ISR for DMA by AC97 Request ---------------------------------*/
//////////
// Function Name : I2S_InitDMA
// Function Description : 
//   This function initialize DMA Controller for I2S Interface
// Input : 	ePort ->  I2S Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
// I2S_InitDMA(AUDIO_PORT1, RXOnly);
void I2S_InitDMA(AUDIO_PORT ePort, I2S_IFMode eIFMode)
{
	I2S_Infor* pInfor	 = I2S_GetInfor(ePort);
	DMA_CH		eDmaCh;
	DMAC*	pI2SDma;
	DMASELECT_eID eDmaId;
	DREQ_SRC eDmaReqSrc;
	u32 uDmaSrcAddr;
	u8 usDmaSrcFix;
	DREQ_SRC eDmaReqDst;
	u32 uDmaDstAddr;
	u8 usDmaDstFix;	
	u32 uTransferSize;
	if (ePort == AUDIO_PORT0)
	{
		
		if ( eIFMode == RXOnly )
		{
			eDmaCh 		= pInfor->m_eDmaRxCh;
			pI2SDma		= &(pInfor->m_oI2SRxDma);
			eDmaId		= eSEL_I2S0_RX;
			eDmaReqSrc	= DMA0_I2S0_RX;				
			uDmaSrcAddr	= I2S0_BASE + rI2SRXD;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= MEM;
			uDmaDstAddr= (u32) pInfor->m_pMemI2SRx;
			usDmaDstFix	= FALSE;
			uTransferSize = pInfor->m_sI2SRxPointer / 4;
		}
		else if ( eIFMode == TXOnly )
		{
			eDmaCh 		= pInfor->m_eDmaTxCh;
			pI2SDma		= &(pInfor->m_oI2STxDma);
			eDmaId		= eSEL_I2S0_TX;
			eDmaReqSrc	= MEM;
			eDmaReqDst	= DMA0_I2S0_TX;
			uDmaSrcAddr	= (u32) pInfor->m_pMemI2STx;
			usDmaSrcFix	= FALSE;
			uDmaDstAddr= I2S0_BASE + rI2STXD;
			usDmaDstFix	= TRUE;			
			uTransferSize = pInfor->m_sI2STxPointer / 4;
		}
		else
		{
			Assert('0');
		}
	}	
	else if ( ePort == AUDIO_PORT1)
	{
		if ( eIFMode == RXOnly )
		{
			eDmaCh 		= pInfor->m_eDmaRxCh;
			pI2SDma		= &(pInfor->m_oI2SRxDma);
			eDmaId		= eSEL_I2S1_RX;
			eDmaReqSrc	= DMA1_I2S1_RX;				
			uDmaSrcAddr	= I2S1_BASE + rI2SRXD;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= MEM;
			uDmaDstAddr= (u32) pInfor->m_pMemI2SRx;
			usDmaDstFix	= FALSE;
			uTransferSize = pInfor->m_sI2SRxPointer / 4;
		}
		else if ( eIFMode == TXOnly )
		{	
			eDmaCh 		= pInfor->m_eDmaTxCh;
			pI2SDma		= &(pInfor->m_oI2STxDma);
			eDmaId		= eSEL_I2S1_TX;
			eDmaReqSrc	= MEM;
			uDmaSrcAddr	= (u32) pInfor->m_pMemI2STx;
			usDmaSrcFix	= FALSE;
			eDmaReqDst	= DMA1_I2S1_TX;
			uDmaDstAddr= I2S1_BASE + rI2STXD;
			usDmaDstFix	= TRUE;			
			uTransferSize = pInfor->m_sI2STxPointer / 4;
		}
		else
		{
			Assert('0');
		}
	}	
	else if (ePort == AUDIO_PORT2)
	{
		
		if ( eIFMode == RXOnly )
		{
			eDmaCh 		= pInfor->m_eDmaRxCh;
			pI2SDma		= &(pInfor->m_oI2SRxDma);
			eDmaId		= eSEL_HSI_RX;
			eDmaReqSrc	= DMA0_HSI_I2SV40_RX;				
			uDmaSrcAddr	= I2SMULTI_BASE + rI2SRXD;
			usDmaSrcFix	= TRUE;
			eDmaReqDst	= MEM;
			uDmaDstAddr= (u32) pInfor->m_pMemI2SRx;
			usDmaDstFix	= FALSE;
			uTransferSize = pInfor->m_sI2SRxPointer / 4;
		}
		else if ( eIFMode == TXOnly )
		{
			eDmaCh 		= pInfor->m_eDmaTxCh;
			pI2SDma		= &(pInfor->m_oI2STxDma);
			eDmaId		= eSEL_HSI_TX;
			eDmaReqSrc	= MEM;
			eDmaReqDst	= DMA0_HSI_I2SV40_TX;
			uDmaSrcAddr	= (u32) pInfor->m_pMemI2STx;
			usDmaSrcFix	= FALSE;
			uDmaDstAddr= I2SMULTI_BASE + rI2STXD;
			usDmaDstFix	= TRUE;			
			uTransferSize = pInfor->m_sI2STxPointer / 4;
		}
		else
		{
			Assert('0');
		}
	}	
	if ( pInfor->m_eDmaUnit == SDMA0 ||pInfor->m_eDmaUnit == SDMA1 )
		SYSC_SelectDMA(eDmaId, 0);
	else
		SYSC_SelectDMA(eDmaId, 1);
	INTC_Enable(pInfor->m_uNumDma);
	DMAC_InitCh(pInfor->m_eDmaUnit , eDmaCh, pI2SDma);
	DMACH_Setup(eDmaCh, false, uDmaSrcAddr, usDmaSrcFix, uDmaDstAddr, usDmaDstFix, WORD, uTransferSize, DEMAND, eDmaReqSrc, eDmaReqDst, SINGLE, pI2SDma);
	DMACH_Start(pI2SDma);	
}


//////////
// Function Name : I2S_DMAStop
// Function Description : 
//   This function stops DMA channel for I2S Interface 
// Input : 	ePort ->  I2S Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
// I2S_InitDMA(AUDIO_PORT1, RXOnly);
void I2S_DMAStop(AUDIO_PORT ePort, I2S_IFMode eIFMode)
{
	I2S_Infor* pInfor	 = I2S_GetInfor(ePort);
	DMAC*	pI2SDma;
	if ( eIFMode == RXOnly )	pI2SDma = &(pInfor->m_oI2SRxDma);
	else if ( eIFMode == TXOnly )	pI2SDma = &(pInfor->m_oI2STxDma);
	DMACH_Stop(pI2SDma);			
}


//////////
// Function Name : I2S_DMAIntrClr
// Function Description : 
//   This function clear DMA channel for I2S Contorller
// Input : 	 ->  I2S Controller
//			eIFMode ->  Interface Channel
// Output : None
// Version : 0.0
// Example 
void I2S_DMAIntrClr(AUDIO_PORT ePort, I2S_IFMode eIFMode)
{
	I2S_Infor* pInfor	 = I2S_GetInfor(ePort);
	if ( eIFMode == RXOnly )
	{
		DMACH_ClearIntPending(&(pInfor->m_oI2SRxDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oI2SRxDma));	
	}
	else if ( eIFMode == TXOnly )
	{
		DMACH_ClearIntPending(&(pInfor->m_oI2STxDma));
		DMACH_ClearErrIntPending(&(pInfor->m_oI2STxDma));	
	}
}


//////////
// Function Name : I2S_SetDMAUnit
// Function Description : This function selec DMA for DMA Request of I2S Interface Contorller.
// Input : 	ePort - I2S Port Number 
//			eUnit - DMA Unit ID
// Output :	None
// Version : v0.0
void I2S_SetDMAUnit(AUDIO_PORT ePort, DMA_UNIT eUnit)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eUnit == DMA0 || eUnit == DMA1 )
	{
		if ( ePort == AUDIO_PORT1 )
		{
			pInfor->m_uNumDma	= NUM_DMA1;					
			pInfor->m_eDmaUnit	= DMA1;		
		}
		else
		{
			pInfor->m_uNumDma	= NUM_DMA0;					
			pInfor->m_eDmaUnit	= DMA0;		
		}
					
	}
	else	 if ( eUnit == SDMA0 || eUnit == SDMA1 )
	{
		if ( ePort == AUDIO_PORT1 )
		{
			pInfor->m_uNumDma	= NUM_SDMA1;		
			pInfor->m_eDmaUnit	= SDMA1;		
		}		
		else
		{
			pInfor->m_uNumDma	= NUM_SDMA0;		
			pInfor->m_eDmaUnit	= SDMA0;		
		}
	}
}


//////////
// Function Name : Isr_I2SDmaRestart
// Function Description : 
//   This function is ISR for DMA Request of AC97 Controller
//		- This ISR restart DMA.
// Input : 	None
// Output : NONE
// Version : v0.1
void __irq Isr_I2SDmaRestart(void)
{
	I2S_Infor* pInfor;
	AUDIO_PORT ePort;	
	DMA_CH eReqCh;
	u32 uDmaUnit = INTC_GetVicIrqStatus(1);
	if ( uDmaUnit == (1 << (NUM_DMA0 % 32)))			
	{
		INTC_Disable(NUM_DMA0);
		pInfor = I2S_GetInfor(AUDIO_PORT0);	
		eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));
		if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(AUDIO_PORT0, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(AUDIO_PORT0, TXOnly);	
		pInfor = I2S_GetInfor(AUDIO_PORT2);	
		if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(AUDIO_PORT2, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(AUDIO_PORT2, TXOnly);	
	}
	else if ( uDmaUnit == (1 << (NUM_DMA1 % 32)))	
	{
		INTC_Disable(NUM_DMA1);
		ePort = AUDIO_PORT1;	 
		pInfor = I2S_GetInfor(ePort);	
		eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));
		if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(ePort, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(ePort, TXOnly);	
	}
	else 				
	{
		uDmaUnit = INTC_GetVicIrqStatus(0);
		if ( uDmaUnit == (1 << (NUM_SDMA0 % 32)))			
		{
			INTC_Disable(NUM_DMA0);
			pInfor = I2S_GetInfor(AUDIO_PORT0);	
			eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));
			if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(AUDIO_PORT0, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(AUDIO_PORT0, TXOnly);	
			pInfor = I2S_GetInfor(AUDIO_PORT2);	
			if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(AUDIO_PORT2, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(AUDIO_PORT2, TXOnly);	
		}
		else if ( uDmaUnit == (1 << (NUM_SDMA1 % 32)))	
		{
			INTC_Disable(NUM_DMA1);
			ePort = AUDIO_PORT1;	 
			pInfor = I2S_GetInfor(ePort);	
			eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));
			if ( eReqCh & pInfor->m_eDmaRxCh)	I2S_DMARestart(ePort, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)	I2S_DMARestart(ePort, TXOnly);	
		}
	}	
	INTC_ClearVectAddr();
}

//////////
// Function Name : Isr_AC97DmaDone
// Function Description : 
//   This function is ISR for DMA Request of AC97 Controller
//		- This ISR stop DMA.
// Input : 	None
// Output : NONE
// Version : v0.1
void __irq Isr_I2SDmaDone(void)
{
	I2S_Infor* pInfor;
	DMA_CH eReqCh;
	u32 uDmaUnit = INTC_GetVicIrqStatus(1);
	if ( uDmaUnit == (1 << (NUM_DMA0 % 32)))	
	{
		INTC_Disable(NUM_DMA0);
		pInfor = I2S_GetInfor(AUDIO_PORT0);		
		eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));	
		if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT0, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT0, TXOnly);
		pInfor = I2S_GetInfor(AUDIO_PORT2);				
		if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT2, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT2, TXOnly);
	}
	else if ( uDmaUnit == (1 << (NUM_DMA1 % 32)))		
	{
		INTC_Disable(NUM_DMA1);
		pInfor = I2S_GetInfor(AUDIO_PORT1);		
		eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));	
		if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT1, RXOnly);	
		if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT1, TXOnly);
	}
	else
	{
		uDmaUnit = INTC_GetVicIrqStatus(0);
		if ( uDmaUnit == (1 << (NUM_DMA0 % 32)))	
		{
			INTC_Disable(NUM_SDMA0);
			pInfor = I2S_GetInfor(AUDIO_PORT0);		
			eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));	
			if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT0, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT0, TXOnly);
			pInfor = I2S_GetInfor(AUDIO_PORT2);					
			if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT2, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT2, TXOnly);
		}
		else if ( uDmaUnit == (1 << (NUM_SDMA1 % 32)))		
		{
			INTC_Disable(NUM_DMA1);
			pInfor = I2S_GetInfor(AUDIO_PORT1);		
			eReqCh = DMACH_GetChannelNumber(&(pInfor->m_oI2SRxDma));	
			if ( eReqCh & pInfor->m_eDmaRxCh)		I2S_DMADone(AUDIO_PORT1, RXOnly);	
			if ( eReqCh & pInfor->m_eDmaTxCh)		I2S_DMADone(AUDIO_PORT1, TXOnly);
		}
	}	
	INTC_ClearVectAddr();
}

//////////
// Function Name : Isr_AC97DmaRestart
// Function Description : 
//   This function restart DMA transfer channel
// Input : 	eCh - AC97 channel
// Output : NONE
// Version : v0.1
void I2S_DMARestart(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	I2SCON_ActiveDMA(ePort, eCh, INACTIVE);
	I2S_DMAIntrClr(ePort, eCh);	
	I2S_InitDMA(ePort, eCh);
	if ( eCh == RXOnly)		UART_Printf("\nI2S %d RX DMA Transfer Restart.\n", ePort);		
	else if ( eCh == TXOnly )	UART_Printf("\nI2S %d TX DMA Transfer Restart.\n", ePort);		
	I2SCON_ActiveDMA(ePort, eCh, ACTIVE);
	INTC_ClearVectAddr();	
}

//////////
// Function Name : I2S_DMADone
// Function Description : 
//   This function stop DMA Transfer.
//		- This ISR restart DMA.
// Input : 	eCh - AC97 channel
// Output : NONE
// Version : v0.1
void I2S_DMADone(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	I2S_DMAIntrClr(ePort, eCh);	
	I2S_SetIntrDone(ePort, eCh, TRUE);
	if ( eCh == RXOnly)		UART_Printf("\nI2S %d RX DMA Transfer Done.\n", ePort);		
	else if ( eCh == TXOnly )	UART_Printf("\nI2S %d TX DMA Transfer Done.\n", ePort);
	INTC_ClearVectAddr();
}

//-----------------------------------------I2S Port Configuration-------------------------------------//
//////////
// Function Name : I2S_InitPort
// Function Description : 
//   This function Set GPIO port as I2S.
// Input : ePort - I2S port number
// Output : NONE
// Version : 
void I2S_InitPort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0:
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_1, 0x3);		// I2S0 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_1, 0x1);	// I2S0 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_0, 0x3);		// I2S0 SCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_0, 0x0);	// I2S0 SCLK Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_2, 0x3);		// I2S0 LRCLK
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_2, 0x0);	// I2S0 LRCLK Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_3, 0x3);		// I2S0 DIN
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_3, 0x0);	// I2S0 DIN Pull Up/Down Disable	
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_4, 0x3);		// I2S0 DOUT
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_4, 0x0);	// I2S0 DOUT Pull Up/Down Disable				
			break;
		case AUDIO_PORT1 :
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_1, 0x3);		// I2S1 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_1, 0x1);	// I2S1 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_0, 0x3);		// I2S1 SCLK
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_0, 0x0);	// I2S1 SCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_2, 0x3);		// I2S1 LRCLk
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_2, 0x0);	// I2S1 LRCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_3, 0x3);		// I2S1 DIN
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_3, 0x0);	// I2S1 DIN Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_4, 0x3);		// I2S1 DOUT		
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_4, 0x0);	// I2S1 DOUT Pull Down Disable				
			break;
		case AUDIO_PORT2:
			//MMC
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_7, 0x5);		// I2S2 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_7, 0x1);	// I2S2 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_6, 0x5);		// I2S2 SCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_6, 0x0);	// I2S2 SCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_8, 0x5);		// I2S2 LRCLk
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_8, 0x0);	// I2S2 LRCLk Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_9, 0x5);		// I2S2 DIN
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_9, 0x0);	// I2S2 DIN Pull Down Disable	
			//SPI
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_4, 0x0);	// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_4, 0x5);		// I2S2 DOUT0
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_5, 0x0);	// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_5, 0x5);		// I2S2 DOUT
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_7, 0x0);	// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_7, 0x5);		// I2S2 DOUT2
			break;
		default :
			Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
			Assert(0);
			break;
	}
}

//////////
// Function Name : I2S_InitPort
// Function Description : 
//   This function Sets GPIO ports as I2SCDCLK. using Only I2SCDCLK OUT PAD		
// Input : ePort - I2S port number
// Output : NONE
// Version : 

void I2S_SetCDCLKPort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0:
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_1, 0x3);	
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_1, 0x1);	// I2S0 CDCLK Pull Down Enable	
			break;
		case AUDIO_PORT1 :
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_1, 0x3);		
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_1, 0x1);	// I2S1 CDCLK Pull Down Enable	
			break;
		case AUDIO_PORT2:
			//MMC
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_7, 0x5);		// I2S2 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_7, 0x1);	// I2S2 CDCLK Pull Down Enable	
			break;
		default :
			Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
			Assert(0);
			break;
	}
}

//////////
// Function Name : I2S_ClosePort
// Function Description : 
//   This function changes GPIO Ports from I2S ports to Input GPIO
// Input : ePort - I2S port number
// Output : NONE
// Version : 
void I2S_ClosePort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0 :
			GPIO_SetFunctionAll(eGPIO_D, 0x0, 0x0);
			GPIO_SetPullUpDownAll(eGPIO_D, 0x0);
			break;
		case AUDIO_PORT1 :
			GPIO_SetFunctionAll(eGPIO_E, 0x0, 0x0);
			GPIO_SetPullUpDownAll(eGPIO_E, 0x0);
			break;
		case AUDIO_PORT2:
			//MMC
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_7, 0);			// I2S2 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_7, 0);		// I2S2 CDCLK Pull Down Enable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_6, 0);			// I2S2 SCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_6, 0x0);	// I2S2 SCLK Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_8, 0);			// I2S2 LRCLk
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_8, 0x0);	// I2S2 LRCLk Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_9, 0);			// I2S2 DIN
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_9, 0);		// I2S2 DIN Pull Down Disable	
			//SPI
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_4, 0);		// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_4, 0);			// I2S2 DOUT0
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_5, 0);		// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_5, 0);			// I2S2 DOUT
			GPIO_SetPullUpDownEach(eGPIO_C, eGPIO_6, 0);		// I2S2 DOUT0 Pull Down Disable	
			GPIO_SetFunctionEach(eGPIO_C, eGPIO_6, 0);			// I2S2 DOUT2
			break;
		default :
			Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
			Assert(0);
			break;
	}
}

//////////
// Function Name : I2S_CloseCDCLKPort
// Function Description : 
//   This function changes GPIO Ports set only I2SCDCLK port.
// Input : ePort - I2S port number
// Output : NONE
// Version : 

void I2S_CloseCDCLKPort(AUDIO_PORT ePort)
{
	switch(ePort)
	{
		case AUDIO_PORT0:
			GPIO_SetFunctionEach(eGPIO_D, eGPIO_1, 0x0);		
			GPIO_SetPullUpDownEach(eGPIO_D, eGPIO_1, 0x0);	// I2S0 CDCLK Pull Down Enable	
			break;
		case AUDIO_PORT1 :
			GPIO_SetFunctionEach(eGPIO_E, eGPIO_1, 0x0);	
			GPIO_SetPullUpDownEach(eGPIO_E, eGPIO_1, 0x0);	// I2S0 CDCLK Pull Down Enable	
			break;
		case AUDIO_PORT2:
			//MMC
			GPIO_SetFunctionEach(eGPIO_H, eGPIO_7, 0x0);		// I2S2 CDCLK
			GPIO_SetPullUpDownEach(eGPIO_H, eGPIO_7, 0x0);	// I2S2 CDCLK Pull Down Enable	
			break;
		default :
			Disp("S3C6410 dose not support Audio Port %d!!\n",ePort);
			Assert(0);
			break;
	}
}

/*---------------------------------- APIs of rI2SCON ---------------------------------*/
//////////
// Function Name : I2SCON_ActiveIF
// Function Description : 
//   This function implements activation/deactivation of I2S Infterface.
// Input : 	ePort		- I2S controller number
//			ucActive	- Enable/Disable
// Output : NONE
// Version : v0.1
void I2SCON_ActiveIF(AUDIO_PORT ePort, u8 ucActive)
{
	u32 uRegValue = 0;	

	uRegValue = I2S_Inp32(ePort, rI2SCON); 	
	if ( ucActive == true)
		uRegValue |= I2S_EnI2sInterface;
	else
		uRegValue &= ~I2S_EnI2sInterface;
	I2S_Outp32(ePort, rI2SCON, uRegValue);	
}

//////////
// Function Name : I2SCON_ActiveDMA
// Function Description : 
//   This function implements activation/deactivation of I2S DMA.
// Input : 	ePort		- I2S controller number
//			eXferMode	- Tx/Rx mode
// Output : NONE
// Version : v0.1
void I2SCON_ActiveDMA(AUDIO_PORT ePort, I2S_IFMode eIFMode, u8 ucActive)
{
	u32 uRegValue = 0;	

	uRegValue = I2S_Inp32(ePort, rI2SCON);
	switch(eIFMode)
	{
		case TXOnly:
			if (ucActive == ACTIVE)
				uRegValue |= I2S_EnTxDma;
			else if (ucActive == INACTIVE)
				uRegValue &= ~I2S_EnTxDma;
			break;
		case RXOnly:
			if (ucActive == ACTIVE)
				uRegValue |= I2S_EnRxDma;
			else if (ucActive == INACTIVE)
				uRegValue &= ~I2S_EnRxDma;
			break;
		case TXRXBoth:
			if (ucActive == ACTIVE)
				uRegValue |= I2S_EnTxDma | I2S_EnRxDma;
			else if (ucActive == INACTIVE)
				uRegValue &= ~I2S_EnTxDma & ~I2S_EnRxDma;
			break;	
	}
	I2S_Outp32(ePort, rI2SCON, uRegValue);	
}

//////////
// Function Name : I2SCON_PauseDMA
// Function Description : 
//   This function implements pause/resume of I2S Channel.
// Input : 	ePort		- I2S controller number
//			eXferMode	- Tx/Rx mode
// Output : NONE
// Version : v0.1
void I2SCON_PauseDMA(AUDIO_PORT ePort, I2S_IFMode eIFMode, u8 ucPause)
{
	u32 uRegValue = 0;	

	uRegValue = I2S_Inp32(ePort, rI2SCON);
	switch(eIFMode)
	{
		case TXOnly:
			uRegValue = 
				(ucPause == PAUSE) ? (uRegValue |= I2S_PaTxDma) : (uRegValue &= ~I2S_PaTxDma);			
			break;
		case RXOnly:
			uRegValue = 
				(ucPause == PAUSE) ? (uRegValue |= I2S_PaRxDma) : (uRegValue &= ~I2S_PaRxDma);
			break;
		case TXRXBoth:
			uRegValue  = 
				(ucPause == PAUSE) ? (uRegValue |= I2S_PaTxDma | I2S_PaRxDma) : (uRegValue &= ~I2S_PaTxDma & ~I2S_PaRxDma);
			break;	
	}
	I2S_Outp32(ePort, rI2SCON, uRegValue);	
}

//////////
// Function Name : I2SCON_PauseIF
// Function Description : 
//   This function implements activation/deactivation of I2S interface.
// Input : 	ePort		- I2S controller number
//			eIFMode	- Tx/Rx Infterface
//			ucPause	- Pause/Play
// Output : NONE
// Version : v0.1
void I2SCON_PauseIF(AUDIO_PORT ePort, I2S_IFMode eIFMode, u8 ucPause)
{
	u32 uRegValue = 0;	

	uRegValue = I2S_Inp32(ePort, rI2SCON);
	switch(eIFMode)
	{
		case TXOnly:
			if (ucPause == PAUSE)
				uRegValue |= I2S_PaTxInterface;
			else if (ucPause == PLAY)
				uRegValue &= ~I2S_PaTxInterface;
			break;
		case RXOnly:
			if (ucPause == PAUSE)
				uRegValue |= I2S_PaRxInterface;
			else if (ucPause == PLAY)
				uRegValue &= ~I2S_PaRxInterface;
			break;
		case TXRXBoth:
			if (ucPause == PAUSE)
				uRegValue |= I2S_PaTxInterface | I2S_PaRxInterface;
			else if (ucPause == PLAY)
				uRegValue &= ~I2S_PaTxInterface & ~I2S_PaRxInterface;
			break;	
	}

	I2S_Outp32(ePort, rI2SCON, uRegValue);	
}

//////////
// Function Name : I2SCON_EnableIntr
// Function Description : 
//   This function enabe or disable Interrupt of I2S interface Contorller.
// Input : 	ePort			- I2S controller			
// 			rhs_eISource	- Interrupt Source
// 			ucActive		- Enable/Disbale
// Output : NONE
// Version : v0.1
void I2SCON_EnableIntr(AUDIO_PORT ePort, I2S_IntrSource rhs_eISource, u8 ucActive)
{
	u32 urI2SCON;
	urI2SCON = I2S_Inp32(ePort, rI2SCON);
	switch(rhs_eISource)
	{
		case I2S_TX:
			if (ucActive == ACTIVE)			
				urI2SCON |= I2S_EnUnderrunIntr;			
			else 			
				urI2SCON &= ~I2S_EnUnderrunIntr;			
			break;		
		case I2S_RX:
			if (ucActive == ACTIVE)
				urI2SCON |= I2S_EnOverrunIntr;		
			else 
				urI2SCON &= ~I2S_EnOverrunIntr;
			break;
	}
	I2S_Outp32(ePort, rI2SCON, urI2SCON);
}

//////////
// Function Name : I2SCON_ChkInterrupt
// Function Description : 
//   This function check Interrupt condition.
// Input : 	ePort		- I2S controller number//			
// Output : I2S_IFMode	- intererupt condition
// Version : v0.1
I2S_IFMode I2SCON_ChkInterrupt(AUDIO_PORT ePort)
{
	u32 urI2SCON;
	urI2SCON = I2S_Inp32(ePort, rI2SCON);
	if ( urI2SCON & I2S_ClrOverrunIntr )
		return RXOnly;
	else if ( urI2SCON & I2S_ClrUnderrunIntr )
		return TXOnly;	
	else if ( urI2SCON & ( I2S_ClrUnderrunIntr | I2S_ClrOverrunIntr ) )
		return TXRXBoth;
	else 
		return TXRXNeither;
}
//////////
// Function Name : I2SCON_ClrOverIntr
// Function Description : 
//   This function clears Overrun Interrupt Bit.
// Input : 	ePort		- I2S controller number//			
// Output : NONE
// Version : v0.1
void I2SCON_ClrOverIntr(AUDIO_PORT ePort)
{	
	u32 uRegValue;
	uRegValue = I2S_Inp32(ePort, rI2SCON)  | I2S_ClrOverrunIntr;
	I2S_Outp32(ePort, rI2SCON, uRegValue);
}

//////////
// Function Name : I2SCON_ClrUnderIntr
// Function Description : 
//   This function clears Underrun Interrupt Bit.
// Input : 	ePort		- I2S controller number			
// Output : NONE
// Version : v0.1
void I2SCON_ClrUnderIntr(AUDIO_PORT ePort)
{
	u32 uRegValue;
	uRegValue = I2S_Inp32(ePort, rI2SCON) | I2S_ClrUnderrunIntr;
	I2S_Outp32(ePort, rI2SCON, uRegValue);
}

//////////
// Function Name : I2SCON_CheckFIFOEmpty
// Function Description : 
//   This function indicates FIFO Empty of Transmit Channel.
// Input : 	ePort		- I2S controller number
//			eCh			- I2S Transmit Channel(RX/TX)
// Output : u8 - FIFOEmpty : TRUE/Fifo not Empty : FALSE
// Version : v0.1
u8 I2SCON_ChkFIFOEmpty(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	u32 uRegValue;
	uRegValue = I2S_Inp32(ePort, rI2SCON);
	if ( eCh == TXOnly )
		uRegValue = uRegValue & I2S_StTxFifoEmpty;
	else if ( eCh == RXOnly )
		uRegValue = uRegValue & I2S_StRxFifoEmpty;
	else
		Assert(0);

	if (!uRegValue)
		return FALSE;
	else
		return TRUE;
}

//////////
// Function Name : I2SCON_ChkFIFOFull
// Function Description : 
//   This function indicates FIFO Full of Transmit Channel.
// Input : 	ePort		- I2S controller number
//			eCh			- I2S Transmit Channel(RX/TX)
// Output : u8 - Fifo full : TRUE/Fifo not full : FALSE
// Version : v0.1
u8 I2SCON_ChkFIFOFull(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	u32 uRegValue;
	uRegValue = I2S_Inp32(ePort, rI2SCON);
	if ( eCh == TXOnly )
		uRegValue = uRegValue & I2S_StTxFifoFull;
	else if ( eCh == RXOnly )
		uRegValue = uRegValue & I2S_StRxFifoFull;
	else
		Assert(0);
	if (!uRegValue)
		return FALSE;
	else
		return TRUE;
}

//////////
// Function Name : I2SCON_ChkExtFIFOEmpty
// Function Description : 
//   This function indicates FIFO Empty of External Transmit Channel 1 and 2.
// Input : 	ePort		- I2S controller number
//			eCh			- I2S Transmit Channel(RX/TX)
// Output : u8 - Fifo full : TRUE/Fifo not full : FALSE
// Version : v0.1
u8 I2SCON_ChkExtFIFOEmpty(AUDIO_PORT ePort, I2S_DCE eFifo)
{
	if ( ePort == AUDIO_PORT2 )
	{
		u32 uRegValue;
		uRegValue = I2S_Inp32(ePort, rI2SCON);
		if (eFifo == I2S_Tx1)
			uRegValue &= (1 << 14);
		else if (eFifo == I2S_Tx2)
			uRegValue &= (1 << 15);		
		else if (eFifo == I2S_AllTx)
			uRegValue &= (1 << 14) & (1 << 15) & (1 << 10);
		else 
			uRegValue &= (1 << 10);				
		if (!uRegValue)
			return FALSE;
		else
			return TRUE;
	}
	else
	{
		Disp("This Function only support I2S2 (Multichannel)!!\n");
		return -1;
	}
}

//////////
// Function Name : I2SCON_ChkExtFIFOFull
// Function Description : 
//   This function indicates FIFO Full of External Transmit Channel 1 and 2.
// Input : 	ePort		- I2S controller number
//			eCh			- I2S Transmit Channel(RX/TX)
// Output : u8 - Fifo full : TRUE/Fifo not full : FALSE
// Version : v0.1
u8 I2SCON_ChkExtFIFOFull(AUDIO_PORT ePort, I2S_DCE eFifo)
{
	if ( ePort == AUDIO_PORT2 )
	{
		u32 uRegValue;
		uRegValue = I2S_Inp32(ePort, rI2SCON);
		if (eFifo == I2S_Tx1)
			uRegValue &= (1 << 12);
		else if (eFifo == I2S_Tx2)
			uRegValue &= (1 << 13);		
		else if (eFifo == I2S_AllTx)
			uRegValue &= (1 << 12) & (1 << 13) & (1 << 8);
		else 
			uRegValue &= (1 << 8);				
		if (!uRegValue)
			return FALSE;
		else
			return TRUE;	
	}
	else
	{
		Disp("This Function only support I2S2 (Multichannel)!!\n");
		return -1;
	}
}


/*---------------------------------- APIs of rI2SMOD ---------------------------------*/
//////////
// Function Name : I2SMOD_SetMode
// Function Description : 
//   This function set all kinds of control bit on I2SMOD.
// Input : 	AUDIO_PORT		- I2S controller number
//			PCMWordLength	- PCM Word Length(8/16/24bit)
//			I2S_CLKSRC			- Root Clock source (Epll/Mpll/Fin/External/PCLK)
//			I2S_IFMode			- Interface(TX/RX/Both)
//			OPMode			- Controller Operating Mode(Master/Slave)
//			I2S_LRCLKPolarity	- LRCLK Polarity(LeftHigh/RightHigh)
//			SerialDataFormat	- Interface Serial Data Format(I2S/MSBJustified/LSBJustified)
//			I2S_RFS				- RFS Value
//			I2S_BFS				- BFS Value
// Output : NONE
// Version : v0.0
void I2SMOD_SetMode(AUDIO_PORT ePort, PCMWordLength eWordLen, I2S_CLKSRC eCLKSRC, I2S_IFMode eCh, OPMode eOpMode, I2S_LRCLKPolarity ePolar, SerialDataFormat eFormat, I2S_RFS eRFS, I2S_BFS eBFS)
{
	u32 urI2SMOD = 0x0;
	I2S_Infor *pInfor = I2S_GetInfor(ePort);	
	urI2SMOD = (eWordLen << 13) | (eOpMode << 11) |(eCh << 8) | (ePolar << 7) | (eFormat << 5) | (eRFS <<3) | (eBFS << 1);
	if (eCLKSRC == I2S_PCLK)
		urI2SMOD |= (0 << 12) | (0 << 10); 
	else if (eCLKSRC == I2S_EXTERNALCDCLK)
		urI2SMOD |= (1 << 12) | (1 << 10); 
	else
		urI2SMOD |= (0 << 12) | (1 << 10); 
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_SetBLC
// Function Description : 
//   This function sets PCM Word Length(BLC) bits of I2SMOD register.
// Input : 	AUDIO_PORT		- I2S controller number
//			PCMWordLength	- PCM Word Length(8/16/24bit)
// Output : NONE
// Version : v0.0
void I2SMOD_SetBLC(AUDIO_PORT ePort, PCMWordLength eWordLen)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 13);
	urI2SMOD |= ((u32) eWordLen << 13);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}


//////////
// Function Name : I2SMOD_GetBLC
// Function Description : 
//   This function gets PCM Word Length(BLC) bits of I2SMOD register.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : PCMWordLength	- PCM Word Length(8/16/24bit)
// Version : v0.0
PCMWordLength I2SMOD_GetBLC(AUDIO_PORT ePort)
{
	return (PCMWordLength) ((I2S_Inp32(ePort, rI2SMOD) & (0x3 << 13)) >> 13);
}

//////////
// Function Name : I2SMOD_SetCLKSource
// Function Description : 
//   This function selects source of I2S Controller Interface
// Input : 	AUDIO_PORT		- I2S controller number
//			I2S_CLKSRC			- Root Clock source (Epll/Mpll/Fin/External/PCLK)
// Output : NONE
// Version : v0.0
void I2SMOD_SetCLKSource(AUDIO_PORT ePort, I2S_CLKSRC eCLKSRC)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x1 << 12) & ~(0x1 << 10);
	if ( eCLKSRC != I2S_PCLK)
	{
		if (eCLKSRC == I2S_EXTERNALCDCLK)
			urI2SMOD |= (1 << 12) | (1 << 10);
		else 
			urI2SMOD |= (1 << 10);
	}		
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);	
}

//////////
// Function Name : I2SMOD_SetInterface
// Function Description : 
//   This function enable interface channel of I2S Controller.
// Input : 	AUDIO_PORT		- I2S controller number
//			I2S_IFMode			- Interface(TX/RX/Both)
// Output : NONE
// Version : v0.0
void I2SMOD_SetInterface(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 8);
	urI2SMOD |= ((u32) eCh << 8);	
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetInterface
// Function Description : 
//   This function gets information of enabling interface channel of I2S Controller.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_IFMode			- Interface(TX/RX/Both)
// Version : v0.0
I2S_IFMode I2SMOD_GetInterface(AUDIO_PORT ePort)
{
	return (I2S_IFMode)((I2S_Inp32(ePort, rI2SMOD) & (0x3 << 8)) >> 8);
}

//////////
// Function Name : I2SMOD_SetOPMode
// Function Description : 
//   This function sets operation mode.
// Input : 	AUDIO_PORT		- I2S controller number
//			OPMode			- Controller Operating Mode(Master/Slave)
// Output : NONE
// Version : v0.0
void I2SMOD_SetOPMode(AUDIO_PORT ePort, OPMode eOpMode)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x1 << 11);
	urI2SMOD |= ((u32) eOpMode << 11);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetOPMode
// Function Description : 
//   This function gets operation mode.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : OPMode			- Controller Operating Mode(Master/Slave)
// Version : v0.0
OPMode I2SMOD_GetOPMode(AUDIO_PORT ePort)
{
	return  (OPMode) ((I2S_Inp32(ePort, rI2SMOD) & (0x1 << 11)) >> 11);
}

//////////
// Function Name : I2SMOD_SetLRPolarity
// Function Description : 
//   This function sets I2SLRCLK Polarity.
// Input : 	AUDIO_PORT		- I2S controller number
//			I2S_LRCLKPolarity	- LRCLK Polarity(LeftHigh/RightHigh)
// Output : NONE
// Version : v0.0
void I2SMOD_SetLRPolarity(AUDIO_PORT ePort, I2S_LRCLKPolarity ePolar)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x1 << 7);
	urI2SMOD |= ((u32) ePolar << 7);	
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetLRPolarity
// Function Description : 
//   This function gets operation mode.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_LRCLKPolarity	- LRCLK Polarity(LeftHigh/RightHigh)
// Version : v0.0
I2S_LRCLKPolarity I2SMOD_GetLRPolarity(AUDIO_PORT ePort)
{
	return (I2S_LRCLKPolarity) ((I2S_Inp32(ePort, rI2SMOD) & (0x1 << 7)) >> 7);
}

//////////
// Function Name : I2SMOD_SetInterfaceFormat
// Function Description : 
//   This function sets Serial Data Fromat.
// Input : 	AUDIO_PORT		- I2S controller number
//			SerialDataFormat	- Serial Data Fromat(I2S/MSBJustified/LSBJustified)
// Output : NONE
// Version : v0.0
void I2SMOD_SetInterfaceFormat(AUDIO_PORT ePort, SerialDataFormat eFormat)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 5);
	urI2SMOD |= ((u32) eFormat << 5);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetDataFormat
// Function Description : 
//   This function gets Serial Data Fromat.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : SerialDataFormat	- Serial Data Fromat(I2S/MSBJustified/LSBJustified)
// Version : v0.0
SerialDataFormat I2SMOD_GetDataFormat(AUDIO_PORT ePort)
{
	return (SerialDataFormat) ((I2S_Inp32(ePort, rI2SMOD) & (0x3 << 5)) >> 5);	
}

//////////
// Function Name : I2SMOD_SetRFS
// Function Description : 
//   This function sets RFS bits.
// Input : 	AUDIO_PORT		- I2S controller number
//			I2S_RFS	- RFS Value
// Output : NONE
// Version : v0.0
void I2SMOD_SetRFS(AUDIO_PORT ePort, I2S_RFS eRFS)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 3);
	urI2SMOD |= ((u32) eRFS << 3);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetRFS
// Function Description : 
//   This function gets RFS value.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_RFS	- RFS Value
// Version : v0.0
I2S_RFS I2SMOD_GetRFS(AUDIO_PORT ePort)
{
	return (I2S_RFS) ((I2S_Inp32(ePort, rI2SMOD) & (0x3 << 3)) >> 3);
}

//////////
// Function Name : I2SMOD_SetBFS
// Function Description : 
//   This function sets BFS bits.
// Input : 	AUDIO_PORT		- I2S controller number
//			I2S_BFS	- BFS Value
// Output : NONE
// Version : v0.0
void I2SMOD_SetBFS(AUDIO_PORT ePort, I2S_BFS eBFS)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 1);
	urI2SMOD |= ((u32) eBFS << 1);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
}

//////////
// Function Name : I2SMOD_GetRFS
// Function Description : 
//   This function gets RFS value.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_BFS	- BFS Value
// Version : v0.0
I2S_BFS I2SMOD_GetBFS(AUDIO_PORT ePort)
{
	return (I2S_BFS) ((I2S_Inp32(ePort, rI2SMOD) & (0x1 << 3)) >> 1);
}

//////////
// Function Name : I2SMOD_GetRFS
// Function Description : 
//   This function gets RFS value.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_BFS	- BFS Value
// Version : v0.0
void I2SMOD_SetDCE(AUDIO_PORT ePort, I2S_DCE eDCE)
{
	u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD) & ~(0x3 << 16);
	urI2SMOD |= ((u32) eDCE << 16);
	I2S_Outp32(ePort, rI2SMOD, urI2SMOD);

}

//////////
// Function Name : I2SMOD_GetRFS
// Function Description : 
//   This function gets RFS value.
// Input : 	AUDIO_PORT		- I2S controller number
// Output : I2S_BFS	- BFS Value
// Version : v0.0
void I2SMOD_SetCDD(AUDIO_PORT ePort, I2S_DCE eDCE, I2S_CDD eCDD)
{
	if ( ePort == AUDIO_PORT2 )
	{
		u32 urI2SMOD = I2S_Inp32(ePort, rI2SMOD);
		if ( eDCE == I2S_Tx1 )
		{
			urI2SMOD &= ~(0x3 << 18);
			urI2SMOD |= (eDCE << 18);
			I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
		}
		else if ( eDCE == I2S_Tx2 )
		{
			urI2SMOD &= ~(0x3 << 20);
			urI2SMOD |= (eDCE << 20);
			I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
		}
		else if ( eDCE == I2S_AllTx )
		{
			urI2SMOD &= ~(0x3 << 18) & ~(0x3 << 20);
			urI2SMOD |= (eDCE << 18) | (eDCE << 20);	
			I2S_Outp32(ePort, rI2SMOD, urI2SMOD);
		}
		else
		{
			Disp("TX FIFO 0 does not support CDD!!\n");			
		}				
	}
	else 
	{
		Disp("This function(CDD) is only I2S 2 Support!!\n");
	}
}


/*---------------------------------- APIs of rI2SFIC ---------------------------------*/
//////////
// Function Name : I2SFIC_AutoFlush
// Function Description : 
//   This function implements the I2S FIFO Flush.
// Input : ePort 		- I2S port number
//		 eIFMode		- I2S Interface
// Output : NONE
// Version : v0.1
void I2SFIC_AutoFlush(AUDIO_PORT ePort, I2S_IFMode eIFMode)
{
	u32 uRegValue = 0;	
	// FIFO Flush
	uRegValue = I2S_Inp32(ePort, rI2SFIC);
	if ( eIFMode == TXOnly )
	{
		uRegValue |= I2S_FluTxFifo;
	}
	else if ( eIFMode == RXOnly )
	{
		uRegValue |= I2S_FluRxFifo;
	}
	else if ( eIFMode == TXRXBoth )
	{
		uRegValue |= I2S_FluTxFifo | I2S_FluRxFifo;
	}
	I2S_Outp32(ePort, rI2SFIC, uRegValue);
	Delay(I2S_FIFOFlusDelay);
	I2S_Outp32(ePort, rI2SFIC, 0);
}

//////////
// Function Name : I2SFIC_GetFIFOLevel
// Function Description : 
//   This function implements the I2S FIFO Flush.
// Input : ePort 		- I2S port number
//		   eIFMode		- I2S Interface
// Output : FIFO Level
// Version : v0.1
u32 I2SFIC_GetFIFOLevel(AUDIO_PORT ePort, I2S_IFMode eIFMode)
{	
	u32 uRegValue = I2S_Inp32(ePort, rI2SFIC);
	if ( eIFMode == TXOnly )
		return ((uRegValue & (0x1f << 8)) >> 8);
	else if ( eIFMode == RXOnly )
		return ((uRegValue & (0x1f << 0)) >> 0);
	else
		Assert(0);
}
/*---------------------------------- APIs of rI2SPSR ---------------------------------*/
//////////
// Function Name : I2SPSR_SetPrescaler
// Function Description : 
//   This function implements the I2S Clock Prescaler.
// Input : 	ePort 		- I2S controller number
//			rhs_uPrsVal	- Pre-scaler Active
// Output : NONE
// Version : v0.1
void I2SPSR_SetPrescaler(AUDIO_PORT ePort, u32 rhs_uPrsVal)
{
	u32 uTemp = 0;
	uTemp= ((1 << 15)) | (rhs_uPrsVal << 8);
	I2S_Outp32(ePort, rI2SPSR, uTemp);
}
//////////
// Function Name : I2SPSR_ActivePRS
// Function Description : 
//   This function implements the I2S Clock Prescaler.
// Input : ePort 		- I2S controller number
//		   uActive		- Pre-scaler Active
// Output : NONE
// Version : v0.1
void I2SPSR_ActivePRS(AUDIO_PORT ePort, u8 uActive)
{
	u32 uTemp;
	uTemp = I2S_Inp32(ePort, rI2SPSR);
	if (uActive == ACTIVE)
		uTemp |= (1 << 15);
	else
		uTemp &= ~(1 << 15);
	I2S_Outp32(ePort, rI2SPSR, uTemp);
}
//////////
// Function Name : I2SPSR_PutPRSValue
// Function Description : 
//   This function implements the I2S Clock Prescaler.
// Input : 	ePort 		- I2S controller number
//			rhs_uPrsVal	- Pre-scaler Active
// Output : NONE
// Version : v0.1
void I2SPSR_PutPRSValue(AUDIO_PORT ePort, u32 rhs_uPrsVal)
{
	u32 uTemp;
	uTemp = I2S_Inp32(ePort, rI2SPSR) & ~(0x3f << 8);	
	uTemp |=(rhs_uPrsVal << 8);
	I2S_Outp32(ePort, rI2SPSR, uTemp);
}
/*---------------------------------- APIs of rI2STXD ---------------------------------*/
//////////
// Function Name : I2STXD_PutData
// Function Description : 
//   This function puts data into TX Fifo.
// Input : 	ePort 		- I2S controller number
//			u32			- 32bit Data
// Output : NONE
// Version : v0.1
void I2STXD_PutData(AUDIO_PORT ePort, u32 uData)
{
	I2S_Outp32(ePort, rI2STXD, uData);
}

//////////
// Function Name : I2STXD_GetData
// Function Description : 
//   This function gets data from TX Fifo.
// Input : 	ePort 		- I2S controller number
// Output : u32			- 32bit Data
// Version : v0.1
u32 I2STXD_GetData(AUDIO_PORT ePort)
{
	return I2S_Inp32(ePort, rI2STXD);

}
/*---------------------------------- APIs of rI2SRXD ---------------------------------*/
//////////
// Function Name : I2SRXD_PutData
// Function Description : 
//   This function puts data into RX Fifo.
// Input : 	ePort 		- I2S controller number
//			u32			- 32bit Data
// Output : NONE
// Version : v0.1
void I2SRXD_PutData(AUDIO_PORT ePort, u32 uData)
{
	I2S_Outp32(ePort, rI2SRXD, uData);
}

//////////
// Function Name : I2SRXD_GetData
// Function Description : 
//   This function gets data from RX Fifo.
// Input : 	ePort 		- I2S controller number
// Output : u32			- 32bit Data
// Version : v0.1
u32 I2SRXD_GetData(AUDIO_PORT ePort)
{
	return I2S_Inp32(ePort, rI2SRXD);
}

/*---------------------------------- SFR Access Functions  ---------------------------------*/
//////////
// Function Name : I2S_Outp32
// Function Description : This function write value to SFR
// Input : 	ePort - I2S Port Number 
//			rhs_eOffset - SFR Offset
//			rhs_uTemp - SFR Value
// Output :	None
// Version : v0.1

void I2S_Outp32(AUDIO_PORT  ePort, I2S_SFR rhs_eOffset, u32 rhs_uTemp) 
{
	if (ePort == AUDIO_PORT0)		Outp32(I2S0_BASE+rhs_eOffset, rhs_uTemp);
	else if (ePort == AUDIO_PORT1)	Outp32(I2S1_BASE+rhs_eOffset, rhs_uTemp);
	else if (ePort == AUDIO_PORT2)	Outp32(I2SMULTI_BASE+rhs_eOffset, rhs_uTemp);
	else		Assert('0');
}

//////////
// Function Name : I2S_Inp32
// Function Description : This function write value to SFR
// Input : 	ePort - I2S Port Number 
//			rhs_eOffset - SFR Offset
// Output :	u32 - 32bit SFR Value
// Version : v0.1
u32  I2S_Inp32(AUDIO_PORT ePort, I2S_SFR rhs_offset)
{
	if (ePort == AUDIO_PORT0)		return Inp32(I2S0_BASE+rhs_offset);
	else if (ePort == AUDIO_PORT1)	return Inp32(I2S1_BASE+rhs_offset);
	else if (ePort == AUDIO_PORT2)	return Inp32(I2SMULTI_BASE+rhs_offset);
	else 	Assert('0');
}

//////////
// Function Name : I2S_DmaStart
// Function Description : This function start I2S Controller by DMA Transfer. 
// 						  It must be called I2S_InitBuffer and I2SMOD_SetMode before this function call.
// Input : 	ePort - I2S Port Number 
//			eCh - enable Channel 
// Output :	None
// Version : v0.1
void	I2S_DmaStart(AUDIO_PORT ePort, I2S_IFMode eCh, u8 uRepeat)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly)
	{
		I2S_InitDMA(ePort, RXOnly);		
		if ( uRepeat == TRUE)
			INTC_SetVectAddr(pInfor->m_uNumDma ,Isr_I2SDmaRestart);		//Repeat DMA Controller
		else 
			INTC_SetVectAddr(pInfor->m_uNumDma ,Isr_I2SDmaDone);			//Stop DMA Controller	
		I2SMOD_SetInterface(ePort, RXOnly);	
		I2SFIC_AutoFlush(ePort, RXOnly);					//RX FIFO Flush	
		I2SCON_EnableIntr(ePort, I2S_RX, DISABLE);		//Disable RX Overrun Interrupt 
		I2SMOD_SetInterface(ePort, RXOnly);			//Set interface mode of I2SMOD 
		I2SCON_ActiveIF(ePort, ACTIVE);					//IIS IF ACTIVE		
		I2SCON_PauseIF(ePort, RXOnly, PLAY);			//Interface Transfer start
		do 
		{			
		} while (I2SCON_ChkFIFOEmpty(ePort, RXOnly));	//Rx FIFO Empty check
		I2SCON_ActiveDMA(ePort, RXOnly, ACTIVE);		//Enable RX DMA
		I2SCON_PauseDMA(ePort, RXOnly, PLAY);			//Play DMA Request
	}
	else if (eCh == TXOnly)
	{
		I2S_InitDMA(ePort, TXOnly);
		INTC_SetVectAddr(pInfor->m_uNumDma ,Isr_I2SDmaRestart);	
		I2SFIC_AutoFlush(ePort, TXOnly);					//FIFO Flush	
		I2SMOD_SetInterface(ePort, TXOnly);			//TX Interface Mode
		I2SCON_EnableIntr(ePort, I2S_TX, DISABLE);		//Disable I2S TXFIFO Underrun Interrupt
		I2SCON_ActiveDMA(ePort, TXOnly, ACTIVE);		//Active DMA request
		I2SCON_PauseDMA(ePort, TXOnly, PLAY);			//No Pause DMA Request	
		
		do
		{
		}while(I2SCON_ChkFIFOFull(ePort, TXOnly));	
		I2SCON_ActiveIF(ePort, ACTIVE);					//IIS IF ACTIVE		
		I2SCON_PauseIF(ePort, TXOnly, PLAY);			//Enable TX Interface			
	}
}

//////////
// Function Name : I2S_DmaStop
// Function Description : This function Stop I2S Controller by DMA Transfer. 
// Input : 	ePort - I2S Port Number 
//			eCh - enable Channel 
// Output :	None
// Version : v0.1
void I2S_DmaStop(AUDIO_PORT ePort, I2S_IFMode eCh)
{
	I2S_Infor* pInfor = I2S_GetInfor(ePort);
	if ( eCh == RXOnly)
	{
		I2S_DMAIntrClr(ePort, RXOnly);	
		I2S_DMAStop(ePort, RXOnly);
		INTC_Disable(pInfor->m_uNumDma);				//Disble Interrupt 
		I2SCON_ActiveDMA(ePort, RXOnly, INACTIVE);		//Disble RX DMA
		I2SCON_PauseIF(ePort, RXOnly, INACTIVE);		//DMA Request Pause	
		I2SFIC_AutoFlush(ePort, RXOnly);					//FIFO FLUSH	
	}
	else if (eCh == TXOnly)
	{
		I2S_DMAIntrClr(ePort, TXOnly);	
		I2S_DMAStop(ePort, TXOnly);
	    	INTC_Disable(pInfor->m_uNumDma);				//Disble Interrupt 
		I2SCON_ActiveDMA(ePort, TXOnly, INACTIVE);		//Disble RX DMA
		I2SCON_PauseIF(ePort, TXOnly, INACTIVE);		//DMA Request Pause	
		I2SFIC_AutoFlush(ePort, TXOnly);					//FIFO FLUSH	
	}
}

